home *** CD-ROM | disk | FTP | other *** search
- ; ANALYSIS.S
- ;************************************************************************
- ;* *
- ;* PC Scheme/Geneva 4.00 Scheme code *
- ;* *
- ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT *
- ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Closure Analysis and Heap Allocation *
- ;* *
- ;*----------------------------------------------------------------------*
- ;* *
- ;* Created by: David Bartley Date: Oct 1985 *
- ;* Revision history: *
- ;* - 18 Jun 92: Renaissance (Borland Compilers, ...) *
- ;* *
- ;* ``In nomine omnipotentii dei'' *
- ;************************************************************************
-
- ; Pass 1
- ;
- ; Mark lambda expressions to be closed (LAMBDA-CLOSED?=T) at the point
- ; of definition whenever any of the following occur:
- ;
- ; -- the identifier bound to the lambda expression is used as a
- ; funarg [p1-id]
- ;
- ; -- the lambda expression is itself used as a funarg
- ; [p1-lambda]
- ;
- ; -- the identifier bound to the lambda expression is modified
- ; by SET! [p1-set!]
- ;
- ; -- the expression is a MULAMBDA [p1-lambda]
- ;
- ; Mark all identifiers which are bound to closures by LETREC:
- ;
- ; -- ID-INIT: the lambda expression the ID was bound to
- ; (else it is NIL) [p1-lambda]
- ;
- ; Pass 2
- ;
- ; Determine which variables must be heap-allocated by gathering the
- ; following facts used later:
- ;
- ; -- ID-SET!?: it is modified by a SET! [p2-set!]
- ;
- ; -- ID-FREEREF?: it is freely referenced by some function
- ;
- ; -- ID-FUNARGSEES?: it is "visible" to a closed function
- ;
- ; We do not compute the transitive closure of functions reachable from
- ; closed functions. Instead, we consider an ID to be funargref'd if
- ; (1) ID is freely referenced from SOME function AND (2) ID is visible,
- ; though not necessarily referenced, from a closed function.
- ;
- ; An ID will be heap-allocated if it is potentially referenced from a
- ; funarg (both ID-FREEREF? and ID-FUNARGSEES? set non-nil) and must
- ; exist at runtime. It exists at runtime if it is modified (ID-SET!?),
- ; or is initialized to some value other than a lambda expression
- ; (ID-INIT=NIL), or the lambda expression it is bound to is closed.
- ;
-
- (define pcs-closure-analysis
- (lambda (exp)
- (letrec
- ;----!
- (
- (p1-exp
- (lambda (x)
- (case (car x)
- (quote '())
- (#!TOKEN (p1-id x))
- (lambda (p1-lambda x))
- (set! (p1-set! x))
- ;; (if (p1-args (cdr x))) treat as a primop
- ;; (begin (p1-args (cdr x))) treat as a primop
- (letrec (p1-letrec x))
- (else (p1-application x))
- )))
-
- (p1-id
- (lambda (id)
- (close-funarg (id-init id))))
-
- (p1-set!
- (lambda (x)
- (p1-id (set!-id x))
- (p1-exp (set!-exp x))))
-
- (p1-lambda
- (lambda (x)
- (create-lambda-label x '())
- (close-funarg x)
- (p1-exp (lambda-body x))))
-
- (p1-letrec
- (lambda (x)
- (let ((pairs (letrec-pairs x)))
- (p1-pairs-1 pairs) ; link up lambda's and id's
- (p1-pairs-2 pairs) ; find funargref's to id's
- (p1-exp (letrec-body x)))))
-
- (p1-pairs-1
- (lambda (pairs)
- (when pairs
- (let* ((pr (car pairs))
- (id (car pr))
- (exp (cadr pr)))
- (when (eq? (car exp) 'lambda)
- (create-lambda-label exp id)
- (set-id-init id exp)
- (when (negative? (lambda-nargs exp))
- (close-funarg exp)))
- (p1-pairs-1 (cdr pairs))))))
-
- (p1-pairs-2
- (lambda (pairs)
- (when pairs
- (let* ((pr (car pairs))
- (id (car pr))
- (exp (cadr pr)))
- (if (eq? (car exp) 'lambda)
- (p1-exp (lambda-body exp))
- (p1-exp exp))
- (p1-pairs-2 (cdr pairs))))))
-
- (p1-application
- (lambda (x)
- (let ((fn (car x))
- (args (cdr x)))
- (p1-args args)
- (cond ((or (atom? fn)
- (eq? (car fn) '#!TOKEN))
- '())
- ((eq? (car fn) 'LAMBDA)
- (p1-exp (lambda-body fn)))
- (else
- (p1-exp fn))))))
-
- (p1-args
- (lambda (args)
- (when args
- (p1-exp (car args))
- (p1-args (cdr args)))))
-
- (close-funarg
- (lambda (fn)
- (when fn
- (set-lambda-closed? fn #T))))
-
- (create-lambda-label
- (lambda (fn id)
- (set-lambda-label fn
- (if (null? id)
- (pcs-make-label 'lambda)
- (cons (id-number id) (id-name id))))))
-
- ;; ------ pass 2 -------
-
- (p2-exp
- (lambda (x env locals)
- (case (car x)
- (quote '())
- (#!TOKEN (p2-id x env locals))
- (lambda (p2-lambda x env locals))
- (set! (p2-set! x env locals))
- ;; (if (p2-args (cdr x) env locals)) treat as a primop
- ;; (begin (p2-args (cdr x) env locals)) treat as a primop
- (letrec (p2-letrec x env locals))
- (else (p2-application x env locals))
- )))
-
- (p2-id
- (lambda (id env locals)
- (when (not (memq id locals))
- (set-id-freeref? id #T))))
-
- (p2-set!
- (lambda (x env locals)
- (let ((id (set!-id x))
- (val (set!-exp x)))
- (set-id-set!? id #T)
- (p2-id id env locals)
- (p2-exp val env locals))))
-
- (p2-lambda
- (lambda (x env locals)
- (let ((bvl (lambda-bvl x)))
- (when (lambda-closed? x)
- (do ((env env (cdr env)))
- ((null? env))
- (do ((rib (car env)(cdr rib)))
- ((null? rib))
- (set-id-funargsees? (car rib) #T))))
- (p2-exp (lambda-body x)
- (cons bvl env)
- bvl))))
-
- (p2-letrec
- (lambda (x env locals)
- (let* ((pairs (letrec-pairs x))
- (bvl (mapcar car pairs))
- (body (letrec-body x))
- (env (cons bvl env))
- (locals (append bvl locals)))
- (p2-pairs pairs env locals)
- (p2-exp body env locals))))
-
- (p2-pairs
- (lambda (pairs env locals)
- (when pairs
- (p2-exp (cadr (car pairs)) env locals)
- (p2-pairs (cdr pairs) env locals))))
-
- ;; p2-application must process IDs in function position
- ;; because they may need to be heap allocated; e.g:
- ;; (lambda (f)
- ;; (lambda (x) ; 'f' must be heap allocated
- ;; (f x))) ; 'f' appears only in function position
-
- (p2-application
- (lambda (x env locals)
- (let ((fn (car x)))
- (if (or (eq? fn 'THE-ENVIRONMENT)
- (eq? fn '%MAKE-HASHED-ENVIRONMENT))
- (smash-the-environment #T env)
- (let ((args (cdr x)))
- (when (eq? fn '%CALL/CC)
- (smash-the-environment #F env))
- (p2-args args env locals)
- (when (pair? fn)
- (if (eq? (car fn) 'LAMBDA)
- (p2-exp (lambda-body fn)
- (cons (lambda-bvl fn) env)
- (lambda-bvl fn))
- (p2-exp fn env locals))))))))
-
- ;; (THE-ENVIRONMENT) requires all visible lexical variables
- ;; to be heap-allocated
-
- (smash-the-environment
- (lambda (smash-all? env)
- (when env
- (do ((rib (car env) ; CDR down this rib
- (cdr rib)))
- ((null? rib))
- (let ((id (car rib))
- (yes #T))
- (set-id-funargsees? id yes)
- (set-id-freeref? id yes)
- (when smash-all?
- (set-id-set!? id yes)
- (close-funarg (id-init id)))))
- (smash-the-environment smash-all? (cdr env))))) ; get the next rib
-
- (p2-args
- (lambda (args env locals)
- (when args
- (p2-exp (car args) env locals)
- (p2-args (cdr args) env locals))))
-
- ;----!
- )
- (begin
- (p1-exp exp)
- (p2-exp exp '() '())
- '())))) ; executed for effect only
-